#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
AutoML连续减半搜索策略示例
Successive Halving Search Strategy Example

本示例演示如何使用Auto-sklearn的连续减半(Successive Halving)算法进行多保真度优化。
连续减半通过逐步淘汰表现差的配置来优化资源分配，实现高效的超参数搜索。

作者: AutoML学习团队
日期: 2024-07-12
"""

import os
import time
import warnings
from datetime import datetime
from pprint import pprint

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import sklearn.datasets
import sklearn.metrics
import sklearn.model_selection
from sklearn.metrics import classification_report, confusion_matrix

from smac.facade.smac_ac_facade import SMAC4AC
from smac.intensification.successive_halving import SuccessiveHalving
from smac.runhistory.runhistory2epm import RunHistory2EPM4LogCost
from smac.scenario.scenario import Scenario

import autosklearn.classification

# 忽略警告信息
warnings.filterwarnings('ignore')

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False


class SuccessiveHalvingController:
    """
    连续减半策略控制器
    
    管理Auto-sklearn的连续减半算法，实现多保真度优化：
    1. 不同预算类型的配置管理 (iterations, subsample, mixed)
    2. 连续减半参数优化 (eta, initial_budget, max_budget)
    3. 多轮淘汰过程监控和分析
    4. 预算效率评估和可视化
    """
    
    def __init__(self, initial_budget=10, max_budget=100, eta=2):
        """
        初始化连续减半控制器
        
        参数:
            initial_budget (float): 初始预算
            max_budget (float): 最大预算
            eta (int): 减半因子
        """
        self.initial_budget = initial_budget
        self.max_budget = max_budget
        self.eta = eta
        self.experiment_results = {}
        self.elimination_history = []
        
        print(f"🎯 初始化连续减半控制器")
        print(f"   初始预算: {initial_budget}")
        print(f"   最大预算: {max_budget}")
        print(f"   减半因子: {eta}")
        
        # 计算预期的淘汰轮次
        budget = initial_budget
        rounds = 0
        while budget <= max_budget:
            budget *= eta
            rounds += 1
        print(f"   预期淘汰轮次: {rounds}")
    
    def get_smac_callback(self, budget_type):
        """
        获取指定预算类型的SMAC回调函数
        
        参数:
            budget_type (str): 预算类型 ('iterations', 'subsample', 'mixed')
            
        返回:
            function: SMAC优化器回调函数
        """
        def smac_callback(scenario_dict, seed, ta, ta_kwargs,
                         metalearning_configurations, n_jobs, dask_client,
                         multi_objective_algorithm, multi_objective_kwargs):
            """连续减半SMAC回调函数"""
            
            if n_jobs > 1 or (dask_client and len(dask_client.nthreads()) > 1):
                raise ValueError(
                    "请确保代码在 `if __name__ == '__main__'` 保护下运行"
                )
            
            scenario = Scenario(scenario_dict)
            
            # 配置初始配置
            if len(metalearning_configurations) > 0:
                default_config = scenario.cs.get_default_configuration()
                initial_configurations = [default_config] + metalearning_configurations
            else:
                initial_configurations = None
            
            # 设置预算类型
            ta_kwargs["budget_type"] = budget_type
            
            return SMAC4AC(
                scenario=scenario,
                rng=seed,
                runhistory2epm=RunHistory2EPM4LogCost,
                tae_runner=ta,
                tae_runner_kwargs=ta_kwargs,
                initial_configurations=initial_configurations,
                run_id=seed,
                
                # 连续减半核心配置
                intensifier=SuccessiveHalving,
                intensifier_kwargs={
                    "initial_budget": self.initial_budget,
                    "max_budget": self.max_budget,
                    "eta": self.eta,
                    "min_chall": 1,  # 最小挑战者数量
                },
                
                n_jobs=n_jobs,
                dask_client=dask_client,
            )
        
        return smac_callback
    
    def create_classifier(self, budget_type, tmp_folder, time_budget=60):
        """
        创建指定预算类型的分类器
        
        参数:
            budget_type (str): 预算类型
            tmp_folder (str): 临时文件夹
            time_budget (int): 时间预算（秒）
            
        返回:
            AutoSklearnClassifier: 配置好的分类器
        """
        print(f"\n🏗️  创建{budget_type}预算类型分类器")
        
        classifier = autosklearn.classification.AutoSklearnClassifier(
            time_left_for_this_task=time_budget,
            per_run_time_limit=int(time_budget / 6),
            tmp_folder=f"{tmp_folder}_{budget_type}",
            
            # 连续减半配置
            get_smac_object_callback=self.get_smac_callback(budget_type),
            
            # 算法选择（支持不同预算类型）
            include_estimators=[
                'extra_trees',          # 支持迭代预算
                'gradient_boosting',    # 支持迭代预算  
                'random_forest',        # 支持迭代预算
                'sgd',                  # 支持迭代预算
                'passive_aggressive',   # 支持迭代预算
            ],
            include_preprocessors=['no_preprocessing'],  # 简化预处理
            
            # 验证策略
            resampling_strategy="holdout",
            resampling_strategy_arguments={"train_size": 0.67},
            
            # 资源控制
            initial_configurations_via_metalearning=0,  # 禁用元学习
            memory_limit=3072,
            n_jobs=1,
            delete_tmp_folder_after_terminate=False,
            disable_evaluator_output=False,
            seed=42
        )
        
        print(f"   ✅ {budget_type}分类器创建完成")
        return classifier
    
    def run_experiment(self, budget_type, X_train, y_train, X_test, y_test, 
                      tmp_folder, time_budget=60):
        """
        运行指定预算类型的实验
        
        参数:
            budget_type (str): 预算类型
            X_train, y_train: 训练数据
            X_test, y_test: 测试数据
            tmp_folder (str): 临时文件夹
            time_budget (int): 时间预算
            
        返回:
            dict: 实验结果
        """
        print(f"\n🚀 开始{budget_type}预算实验")
        
        # 创建分类器
        classifier = self.create_classifier(budget_type, tmp_folder, time_budget)
        
        # 训练模型
        start_time = time.time()
        classifier.fit(X_train, y_train, dataset_name="breast_cancer")
        end_time = time.time()
        
        training_time = end_time - start_time
        
        # 评估性能
        predictions = classifier.predict(X_test)
        probabilities = classifier.predict_proba(X_test)
        
        # 计算评估指标
        metrics = {
            'accuracy': sklearn.metrics.accuracy_score(y_test, predictions),
            'precision': sklearn.metrics.precision_score(y_test, predictions, average='weighted'),
            'recall': sklearn.metrics.recall_score(y_test, predictions, average='weighted'),
            'f1_score': sklearn.metrics.f1_score(y_test, predictions, average='weighted'),
            'auc': sklearn.metrics.roc_auc_score(y_test, probabilities[:, 1]),
            'confusion_matrix': confusion_matrix(y_test, predictions)
        }
        
        # 模型信息
        models = classifier.show_models()
        model_info = {
            'model_count': len(models),
            'algorithm_diversity': len(set(type(model).__name__ for _, model in models.items())),
            'ensemble_weights': dict(models) if models else {}
        }
        
        # 统计信息
        statistics = classifier.sprint_statistics()
        
        result = {
            'budget_type': budget_type,
            'training_time': training_time,
            'metrics': metrics,
            'model_info': model_info,
            'statistics': statistics,
            'classifier': classifier,
            'timestamp': datetime.now()
        }
        
        self.experiment_results[budget_type] = result
        
        print(f"   ✅ {budget_type}实验完成")
        print(f"   训练时间: {training_time:.2f}秒")
        print(f"   准确率: {metrics['accuracy']:.4f}")
        print(f"   AUC: {metrics['auc']:.4f}")
        
        return result


class BudgetTypeAnalyzer:
    """
    预算类型分析器
    
    分析和比较不同预算类型的性能表现，包括收敛分析、效率评估等。
    """
    
    def __init__(self):
        """初始化预算类型分析器"""
        self.comparison_results = {}
        
    def compare_budget_types(self, experiment_results):
        """
        比较不同预算类型的性能
        
        参数:
            experiment_results (dict): 实验结果字典
            
        返回:
            dict: 比较结果
        """
        print(f"\n📊 预算类型性能对比分析")
        
        comparison = {}
        
        # 性能指标对比
        for budget_type, result in experiment_results.items():
            comparison[budget_type] = {
                'accuracy': result['metrics']['accuracy'],
                'auc': result['metrics']['auc'],
                'training_time': result['training_time'],
                'model_count': result['model_info']['model_count'],
                'algorithm_diversity': result['model_info']['algorithm_diversity']
            }
        
        # 计算相对性能
        if len(comparison) > 1:
            budget_types = list(comparison.keys())
            
            # 找出最佳性能作为基准
            best_accuracy = max(comparison[bt]['accuracy'] for bt in budget_types)
            best_auc = max(comparison[bt]['auc'] for bt in budget_types)
            min_time = min(comparison[bt]['training_time'] for bt in budget_types)
            
            for budget_type in budget_types:
                comparison[budget_type]['relative_accuracy'] = \
                    comparison[budget_type]['accuracy'] / best_accuracy
                comparison[budget_type]['relative_auc'] = \
                    comparison[budget_type]['auc'] / best_auc
                comparison[budget_type]['time_efficiency'] = \
                    min_time / comparison[budget_type]['training_time']
        
        self.comparison_results = comparison
        
        # 打印对比结果
        for budget_type, metrics in comparison.items():
            print(f"\n📈 {budget_type.upper()}预算类型:")
            print(f"   准确率: {metrics['accuracy']:.4f}")
            print(f"   AUC: {metrics['auc']:.4f}")
            print(f"   训练时间: {metrics['training_time']:.2f}秒")
            print(f"   模型数量: {metrics['model_count']}")
            if 'relative_accuracy' in metrics:
                print(f"   相对准确率: {metrics['relative_accuracy']:.3f}")
                print(f"   时间效率: {metrics['time_efficiency']:.3f}")
        
        return comparison
    
    def analyze_budget_efficiency(self, experiment_results):
        """
        分析预算使用效率
        
        参数:
            experiment_results (dict): 实验结果
            
        返回:
            dict: 效率分析结果
        """
        print(f"\n⚡ 预算效率分析")
        
        efficiency_analysis = {}
        
        for budget_type, result in experiment_results.items():
            accuracy = result['metrics']['accuracy']
            time_cost = result['training_time']
            
            # 计算效率指标
            accuracy_per_second = accuracy / time_cost
            auc_per_second = result['metrics']['auc'] / time_cost
            
            efficiency_analysis[budget_type] = {
                'accuracy_per_second': accuracy_per_second,
                'auc_per_second': auc_per_second,
                'models_per_second': result['model_info']['model_count'] / time_cost,
                'efficiency_score': (accuracy * result['metrics']['auc']) / time_cost
            }
            
            print(f"\n⚡ {budget_type.upper()}效率指标:")
            print(f"   准确率/秒: {accuracy_per_second:.6f}")
            print(f"   AUC/秒: {auc_per_second:.6f}")
            print(f"   综合效率分数: {efficiency_analysis[budget_type]['efficiency_score']:.6f}")
        
        return efficiency_analysis


class SuccessiveHalvingVisualizer:
    """
    连续减半可视化器
    
    创建各种可视化图表展示连续减半的性能和行为特征。
    """
    
    def __init__(self, output_dir="../results"):
        """
        初始化可视化器
        
        参数:
            output_dir (str): 输出目录
        """
        self.output_dir = output_dir
        os.makedirs(output_dir, exist_ok=True)
        
        # 设置图表风格
        plt.style.use('default')
        sns.set_palette("husl")
    
    def create_budget_comparison_chart(self, experiment_results):
        """
        创建预算类型对比图表
        
        参数:
            experiment_results (dict): 实验结果
        """
        budget_types = list(experiment_results.keys())
        
        if len(budget_types) < 2:
            print("⚠️  需要至少2种预算类型才能创建对比图表")
            return
        
        fig, axes = plt.subplots(2, 2, figsize=(15, 10))
        fig.suptitle('连续减半预算类型对比分析', fontsize=16, fontweight='bold')
        
        # 准备数据
        accuracies = [experiment_results[bt]['metrics']['accuracy'] for bt in budget_types]
        aucs = [experiment_results[bt]['metrics']['auc'] for bt in budget_types]
        times = [experiment_results[bt]['training_time'] for bt in budget_types]
        model_counts = [experiment_results[bt]['model_info']['model_count'] for bt in budget_types]
        
        colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A'][:len(budget_types)]
        
        # 1. 准确率对比
        bars1 = axes[0, 0].bar(budget_types, accuracies, color=colors)
        axes[0, 0].set_title('准确率对比')
        axes[0, 0].set_ylabel('准确率')
        axes[0, 0].set_ylim(0.9, 1.0)
        for i, v in enumerate(accuracies):
            axes[0, 0].text(i, v + 0.002, f'{v:.4f}', ha='center', va='bottom')
        
        # 2. AUC对比
        bars2 = axes[0, 1].bar(budget_types, aucs, color=colors)
        axes[0, 1].set_title('AUC对比')
        axes[0, 1].set_ylabel('AUC值')
        axes[0, 1].set_ylim(0.9, 1.0)
        for i, v in enumerate(aucs):
            axes[0, 1].text(i, v + 0.002, f'{v:.4f}', ha='center', va='bottom')
        
        # 3. 训练时间对比
        bars3 = axes[1, 0].bar(budget_types, times, color=colors)
        axes[1, 0].set_title('训练时间对比')
        axes[1, 0].set_ylabel('训练时间 (秒)')
        for i, v in enumerate(times):
            axes[1, 0].text(i, v + max(times)*0.01, f'{v:.1f}s', ha='center', va='bottom')
        
        # 4. 模型数量对比
        bars4 = axes[1, 1].bar(budget_types, model_counts, color=colors)
        axes[1, 1].set_title('集成模型数量对比')
        axes[1, 1].set_ylabel('模型数量')
        for i, v in enumerate(model_counts):
            axes[1, 1].text(i, v + 0.1, str(v), ha='center', va='bottom')
        
        plt.tight_layout()
        plt.savefig(os.path.join(self.output_dir, 'budget_comparison.png'), 
                   dpi=300, bbox_inches='tight')
        plt.show()
    
    def create_efficiency_analysis_chart(self, efficiency_analysis):
        """
        创建效率分析图表
        
        参数:
            efficiency_analysis (dict): 效率分析结果
        """
        budget_types = list(efficiency_analysis.keys())
        
        fig, axes = plt.subplots(1, 2, figsize=(15, 6))
        fig.suptitle('预算效率分析', fontsize=14, fontweight='bold')
        
        # 1. 效率指标雷达图
        metrics = ['准确率/秒', 'AUC/秒', '模型数/秒', '综合效率']
        
        # 归一化数据用于雷达图
        all_values = []
        for bt in budget_types:
            values = [
                efficiency_analysis[bt]['accuracy_per_second'],
                efficiency_analysis[bt]['auc_per_second'],
                efficiency_analysis[bt]['models_per_second'],
                efficiency_analysis[bt]['efficiency_score']
            ]
            all_values.append(values)
        
        # 归一化到0-1范围
        max_values = [max(vals) for vals in zip(*all_values)]
        normalized_values = []
        for values in all_values:
            normalized = [v/max_v for v, max_v in zip(values, max_values)]
            normalized_values.append(normalized)
        
        # 创建雷达图
        angles = np.linspace(0, 2 * np.pi, len(metrics), endpoint=False).tolist()
        angles += angles[:1]
        
        ax = plt.subplot(1, 2, 1, projection='polar')
        colors = ['#FF6B6B', '#4ECDC4', '#45B7D1']
        
        for i, (bt, norm_vals) in enumerate(zip(budget_types, normalized_values)):
            values = norm_vals + norm_vals[:1]
            ax.plot(angles, values, 'o-', linewidth=2, label=bt.upper(), color=colors[i])
            ax.fill(angles, values, alpha=0.25, color=colors[i])
        
        ax.set_xticks(angles[:-1])
        ax.set_xticklabels(metrics)
        ax.set_ylim(0, 1)
        ax.set_title('效率指标雷达图', pad=20)
        ax.legend(loc='upper right', bbox_to_anchor=(1.3, 1.0))
        
        # 2. 综合效率排名
        efficiency_scores = [efficiency_analysis[bt]['efficiency_score'] for bt in budget_types]
        sorted_indices = np.argsort(efficiency_scores)[::-1]
        sorted_types = [budget_types[i] for i in sorted_indices]
        sorted_scores = [efficiency_scores[i] for i in sorted_indices]
        
        axes[1].barh(sorted_types, sorted_scores, color=['#FFD700', '#C0C0C0', '#CD7F32'][:len(budget_types)])
        axes[1].set_title('综合效率排名')
        axes[1].set_xlabel('效率分数')
        
        for i, v in enumerate(sorted_scores):
            axes[1].text(v + max(sorted_scores)*0.01, i, f'{v:.6f}', va='center')
        
        plt.tight_layout()
        plt.savefig(os.path.join(self.output_dir, 'efficiency_analysis.png'), 
                   dpi=300, bbox_inches='tight')
        plt.show()
    
    def create_confusion_matrix_grid(self, experiment_results):
        """
        创建混淆矩阵网格对比
        
        参数:
            experiment_results (dict): 实验结果
        """
        budget_types = list(experiment_results.keys())
        n_types = len(budget_types)
        
        if n_types == 0:
            return
        
        fig, axes = plt.subplots(1, n_types, figsize=(5*n_types, 4))
        if n_types == 1:
            axes = [axes]
        
        fig.suptitle('不同预算类型混淆矩阵对比', fontsize=14, fontweight='bold')
        
        colors = ['Blues', 'Oranges', 'Greens', 'Purples']
        
        for i, budget_type in enumerate(budget_types):
            cm = experiment_results[budget_type]['metrics']['confusion_matrix']
            
            sns.heatmap(cm, annot=True, fmt='d', cmap=colors[i % len(colors)],
                       xticklabels=['良性', '恶性'], 
                       yticklabels=['良性', '恶性'],
                       ax=axes[i])
            axes[i].set_title(f'{budget_type.upper()}预算')
            axes[i].set_xlabel('预测类别')
            if i == 0:
                axes[i].set_ylabel('真实类别')
        
        plt.tight_layout()
        plt.savefig(os.path.join(self.output_dir, 'confusion_matrix_grid.png'), 
                   dpi=300, bbox_inches='tight')
        plt.show()


def main():
    """
    主函数：演示AutoML连续减半搜索策略
    """
    print("🎯 AutoML连续减半搜索策略示例")
    print("=" * 60)
    
    # 1. 数据加载和预处理
    print("\n📊 加载Wisconsin乳腺癌数据集")
    X, y = sklearn.datasets.load_breast_cancer(return_X_y=True)
    X_train, X_test, y_train, y_test = sklearn.model_selection.train_test_split(
        X, y, test_size=0.3, random_state=42, stratify=y
    )
    
    print(f"   数据集形状: {X.shape}")
    print(f"   训练集: {X_train.shape[0]}样本")
    print(f"   测试集: {X_test.shape[0]}样本")
    print(f"   特征数量: {X_train.shape[1]}个")
    print(f"   类别分布 - 训练集: 良性{np.sum(y_train==0)}, 恶性{np.sum(y_train==1)}")
    print(f"   类别分布 - 测试集: 良性{np.sum(y_test==0)}, 恶性{np.sum(y_test==1)}")
    
    # 2. 创建连续减半控制器
    controller = SuccessiveHalvingController(
        initial_budget=10.0,    # 初始预算
        max_budget=100.0,       # 最大预算
        eta=2                   # 减半因子
    )
    
    tmp_folder = f"/tmp/autosklearn_successive_halving_{int(time.time())}"
    time_budget = 40  # 每个实验40秒
    
    # 3. 运行不同预算类型的实验
    budget_types = ['iterations', 'subsample', 'mixed']
    experiment_results = {}
    
    total_start_time = time.time()
    
    for budget_type in budget_types:
        try:
            result = controller.run_experiment(
                budget_type, X_train, y_train, X_test, y_test, 
                tmp_folder, time_budget
            )
            experiment_results[budget_type] = result
            
        except Exception as e:
            print(f"❌ {budget_type}实验失败: {str(e)}")
            continue
    
    total_end_time = time.time()
    total_time = total_end_time - total_start_time
    
    # 4. 性能分析
    if experiment_results:
        analyzer = BudgetTypeAnalyzer()
        
        # 预算类型对比分析
        comparison_results = analyzer.compare_budget_types(experiment_results)
        
        # 效率分析
        efficiency_analysis = analyzer.analyze_budget_efficiency(experiment_results)
        
        # 5. 可视化分析
        print(f"\n📊 生成可视化分析图表")
        visualizer = SuccessiveHalvingVisualizer("../results")
        
        # 预算对比图表
        visualizer.create_budget_comparison_chart(experiment_results)
        
        # 效率分析图表
        visualizer.create_efficiency_analysis_chart(efficiency_analysis)
        
        # 混淆矩阵对比
        visualizer.create_confusion_matrix_grid(experiment_results)
        
        # 6. 详细结果报告
        print(f"\n📋 详细实验结果")
        
        for budget_type, result in experiment_results.items():
            print(f"\n🎯 {budget_type.upper()}预算详细结果:")
            print(f"   最终集成模型:")
            pprint(result['classifier'].show_models(), indent=6)
            print(f"\n   训练统计信息:")
            print(result['classifier'].sprint_statistics())
        
        # 7. 推荐最佳预算类型
        print(f"\n🏆 预算类型推荐")
        
        if comparison_results:
            # 找出综合表现最佳的预算类型
            best_accuracy_type = max(comparison_results.keys(), 
                                   key=lambda x: comparison_results[x]['accuracy'])
            best_efficiency_type = max(efficiency_analysis.keys(),
                                     key=lambda x: efficiency_analysis[x]['efficiency_score'])
            
            print(f"   准确率最佳: {best_accuracy_type.upper()} "
                  f"({comparison_results[best_accuracy_type]['accuracy']:.4f})")
            print(f"   效率最佳: {best_efficiency_type.upper()} "
                  f"(效率分数: {efficiency_analysis[best_efficiency_type]['efficiency_score']:.6f})")
            
            # 综合推荐
            if best_accuracy_type == best_efficiency_type:
                print(f"   🎉 推荐使用: {best_accuracy_type.upper()} "
                      f"(准确率和效率均最佳)")
            else:
                print(f"   💡 根据需求选择:")
                print(f"     - 追求最高准确率: {best_accuracy_type.upper()}")
                print(f"     - 追求最高效率: {best_efficiency_type.upper()}")
        
        # 8. 连续减半效果评估
        print(f"\n📈 连续减半算法效果评估")
        
        avg_accuracy = np.mean([r['metrics']['accuracy'] for r in experiment_results.values()])
        avg_time = np.mean([r['training_time'] for r in experiment_results.values()])
        
        print(f"   平均准确率: {avg_accuracy:.4f}")
        print(f"   平均训练时间: {avg_time:.2f}秒")
        print(f"   成功实验数: {len(experiment_results)}/{len(budget_types)}")
        
        # 与理论预期对比
        expected_rounds = int(np.log(controller.max_budget / controller.initial_budget) / 
                            np.log(controller.eta)) + 1
        print(f"   理论淘汰轮次: {expected_rounds}")
        print(f"   预算范围: {controller.initial_budget} → {controller.max_budget}")
        print(f"   减半因子: {controller.eta}")
    
    # 9. 最终总结
    print(f"\n🎉 连续减半策略演示完成!")
    print(f"   总执行时间: {total_time:.2f}秒")
    print(f"   成功实验: {len(experiment_results)}个")
    
    if experiment_results:
        best_result = max(experiment_results.values(), 
                         key=lambda x: x['metrics']['accuracy'])
        print(f"   最佳准确率: {best_result['metrics']['accuracy']:.4f} "
              f"({best_result['budget_type']}预算)")
    
    # 10. 清理建议
    print(f"\n🧹 资源清理:")
    for budget_type in budget_types:
        print(f"   {budget_type}临时文件: {tmp_folder}_{budget_type}")
    print(f"   可视化结果: ../results/")
    
    return controller, experiment_results, comparison_results if experiment_results else {}


if __name__ == "__main__":
    # 设置随机种子以确保结果可重现
    np.random.seed(42)
    
    try:
        controller, experiment_results, comparison_results = main()
        print(f"\n✅ 程序执行成功!")
        
    except KeyboardInterrupt:
        print(f"\n⚠️  程序被用户中断")
        
    except Exception as e:
        print(f"\n❌ 程序执行失败: {str(e)}")
        import traceback
        traceback.print_exc()
        
    finally:
        print(f"\n👋 感谢使用AutoML连续减半示例!")